home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / rpc / rpcOutput.c < prev    next >
C/C++ Source or Header  |  1991-03-16  |  12KB  |  369 lines

  1. /*
  2.  * rpcOutput.c --
  3.  *
  4.  *    The output routine for the RPC system.  Large packets are
  5.  *    fragmented upon ouput here.
  6.  *
  7.  * Copyright 1986 Regents of the University of California
  8.  * All rights reserved.
  9.  */
  10.  
  11. #ifndef lint
  12. static char rcsid[] = "$Header: /sprite/src/kernel/rpc/RCS/rpcOutput.c,v 9.4 90/11/05 21:24:59 jhh Exp Locker: mgbaker $ SPRITE (Berkeley)";
  13. #endif /* not lint */
  14.  
  15.  
  16. #include <sprite.h>
  17. #include <mach.h>
  18. #include <rpc.h>
  19. #include <rpcInt.h>
  20. #include <rpcTrace.h>
  21. #include <net.h>
  22. #include <proc.h>
  23. #include <sync.h>
  24. #include <status.h>
  25. #include <dbg.h>
  26.  
  27. /*
  28.  * A delay variable that represents our preferred inter-fragment delay.
  29.  * This is told to other machines by including it in the RPC header.
  30.  * They use it to set the delay between packets in a fragmented send.
  31.  */
  32. unsigned    short rpcMyDelay;
  33. unsigned    short rpcOutputRate;
  34. short    rpcDelay[NET_NUM_SPRITE_HOSTS];
  35.  
  36. short rpcLastDelay;
  37.  
  38. #ifdef PRINT_PACKETS
  39. Boolean rpcDumpPackets = FALSE;
  40. #endif /* PRINT_PACKETS */
  41.  
  42.  
  43. /*
  44.  *----------------------------------------------------------------------
  45.  *
  46.  * RpcOutput --
  47.  *
  48.  *      Send a message to the host specified by spriteID.  Packets over a
  49.  *      certain size are fragmented by this routine into several datagrams
  50.  *      and reassembled by the dispatch routine of the receiver.  Our
  51.  *      caller has to pass in an array of buffer specifications that this
  52.  *      routine uses if it has to fragment the message.  The RPC header
  53.  *      and the dontSendMask are also used in conjuction with fragmented
  54.  *      packets.
  55.  *      Master Lock note: This routine may busy wait for a few hundred
  56.  *      microseconds in between sending successive packets of a large
  57.  *      message.  This delay is defeated if there is a Master Lock held.
  58.  *      *mutexPtr, if non-NIL, is released during this delay, and then
  59.  *      reaquired.  (This is done because the DMA ethernet driver needs an
  60.  *      interrupt serviced after each packet output.  Things work without
  61.  *      enabling interrupts, but the packets get queued for output until
  62.  *      after the caller of RpcOutput releases the MasterLock.  This
  63.  *      causes one big delay between the 1rst and 2nd packet, and no delay
  64.  *      between ones after that.)
  65.  *
  66.  * Results:
  67.  *    SUCCESS on non-fragmented sends, or an error code related
  68.  *    to fragmenting.
  69.  *
  70.  * Side effects:
  71.  *    Call the ethernet output routine and trace.
  72.  *
  73.  *----------------------------------------------------------------------
  74.  */
  75. ReturnStatus
  76. RpcOutput(spriteID, rpcHdrPtr, message, fragment, dontSendMask, mutexPtr)
  77.     int            spriteID;    /* Destination host */
  78.     register RpcHdr    *rpcHdrPtr;    /* The RPC header. */
  79.     RpcBufferSet    *message;    /* A set of 4 scatter/gather vector
  80.                      * elements that specify where the proto
  81.                      * header, RPC header, parameters, 
  82.                      * and data are. */
  83.     RpcBufferSet    *fragment;    /* An array of buffer sets used if
  84.                      * the message needs to be
  85.                      * fragmented.  This needs to be
  86.                      * previously set up so that the
  87.                      * first buffer references valid
  88.                      * storage for an RPC header. */
  89.     unsigned int    dontSendMask;    /* For fragmenting.  Bits set in this
  90.                      * mask suppress sending of the
  91.                      * corresponding fragment.  A good
  92.                      * value for this is returned in
  93.                      * partial acknowlegment messages */
  94.     Sync_Semaphore    *mutexPtr;    /* This mutex is released while we
  95.                      * output the message.  If NIL, no
  96.                      * mutex is released.  This is done
  97.                      * in honor of DMA interfaces that
  98.                      * interrupt after they output a packet.
  99.                      */
  100. {
  101.     Net_Route        *routePtr;
  102.     ReturnStatus    status;
  103.     Boolean        newVersion = FALSE;
  104. #ifdef PRINT_PACKETS
  105.     if (rpcDumpPackets) {
  106.     register unsigned short *shortPtr;
  107.     register int i;
  108.  
  109.     printf("RpcOutput - Raw packet at %x:\n", rpcHdrPtr);
  110.     shortPtr = (unsigned short *)rpcHdrPtr;
  111.     for (i=0 ; i<sizeof(RpcHdr)/2 ; i++) {
  112.         printf("%x ", *shortPtr);
  113.         shortPtr++;
  114.         if (((i+1)%8) == 0) {
  115.         printf("\n");
  116.         }
  117.     }
  118.     printf("\n");
  119.  
  120.     printf("RpcOutput - buffer set:\n");
  121.     printf("%x %x\n", message->rpcHdrBuffer.bufAddr,
  122.                message->rpcHdrBuffer.length);
  123.     printf("%x %x\n", message->paramBuffer.bufAddr,
  124.                message->paramBuffer.length);
  125.     printf("%x %x\n", message->dataBuffer.bufAddr,
  126.                message->dataBuffer.length);
  127.     }
  128. #endif /* PRINT_PACKETS */
  129.     /*
  130.      * Mark our packets if we aren't up all the way.  This means that the
  131.      * other host won't pay attention to our packets in terms of recovery.
  132.      */
  133.     if (!rpcServiceEnabled) {
  134.     rpcHdrPtr->flags |= RPC_NOT_ACTIVE;
  135.     }
  136.     /* 
  137.      * Find a route to the host. 
  138.      */
  139.     routePtr = Net_IDToRoute(spriteID, 0, TRUE, mutexPtr, 0);
  140.     if (routePtr == (Net_Route *) NIL) {
  141.     return RPC_INTERNAL_ERROR;
  142.     }
  143.     if (routePtr->interPtr->netType == NET_NETWORK_ULTRA) {
  144.     newVersion = TRUE;
  145.     }
  146.     /*
  147.      * Check to see if we have to fragment.   Note that we pack the first
  148.      * fragment as full as possible so that it might contain more than
  149.      * 1K of data.  If we fragment, however, we break things on 1K boundaries.
  150.      */
  151.     if (rpcHdrPtr->paramSize + rpcHdrPtr->dataSize >
  152.     routePtr->maxBytes - sizeof(RpcHdr)) {
  153.     if (rpcHdrPtr->paramSize > RPC_MAX_PARAMSIZE) {
  154.         return(RPC_PARAMS_TOOBIG);
  155.     } else if (rpcHdrPtr->dataSize > RPC_MAX_DATASIZE) {
  156.         return(RPC_DATA_TOOBIG);
  157.     } else {
  158.         /*
  159.          * Send a fragmented message.
  160.          */
  161.         register int dataSize, paramSize;    /* Size remaining in data and
  162.                          * parameter areas that needs
  163.                          * to go in subsequent frags. */
  164.         int dataOffset, paramOffset;    /* Offset of fragment data */
  165.         int frag;                /* Fragment index */
  166.         int nfrags;                /* Total number of fragments */
  167.         int delay;                /* Inter-fragment delay */
  168.         register int fragID;        /* Bitmask ID of fragment.  The
  169.                          * I'th bit of this is set on
  170.                          * the I'th fragment. */
  171.         register int sendFragMask;        /* Complement of the dont-send
  172.                          * mask. */
  173.         register RpcHdr *fragRpcHdrPtr;    /* RPC header of a fragment */
  174.  
  175.         dataSize = rpcHdrPtr->dataSize;
  176.         paramSize = rpcHdrPtr->paramSize;
  177.  
  178.         /*
  179.          * Loop one time to compute and record the sizes of the
  180.          * parameter and data areas of each fragment.
  181.          */
  182.         nfrags = 0;
  183.         dataOffset = 0;
  184.         paramOffset = 0;
  185.         while (dataSize > 0 || paramSize > 0) {
  186.         register int dlen, plen;
  187.  
  188.         /*
  189.          * Fill the fragments with the parameter area followed by
  190.          * the data area.  The max size ethernet packet is used
  191.          * for best throughput.
  192.          */
  193.         if (paramSize) {
  194.             plen = (routePtr->maxBytes - sizeof(RpcHdr));
  195.             plen = (plen > paramSize ? paramSize : plen);
  196.             paramSize -= plen;
  197.         } else {
  198.             plen = 0;
  199.         }
  200.         if (dataSize) {
  201.             dlen = (routePtr->maxBytes - sizeof(RpcHdr) - plen);
  202.             dlen = (dlen > dataSize ? dataSize : dlen);
  203.             dataSize -= dlen;
  204.         } else {
  205.             dlen = 0;
  206.         }
  207.         fragRpcHdrPtr = (RpcHdr *)fragment[nfrags].rpcHdrBuffer.bufAddr;
  208.  
  209.         fragRpcHdrPtr->paramSize = plen;
  210.         fragRpcHdrPtr->dataSize = dlen;
  211.         fragRpcHdrPtr->paramOffset = paramOffset;
  212.         fragRpcHdrPtr->dataOffset = dataOffset;
  213.  
  214.         fragment[nfrags].paramBuffer.length = plen;
  215.         fragment[nfrags].paramBuffer.bufAddr =
  216.             message->paramBuffer.bufAddr + paramOffset;
  217.  
  218.         fragment[nfrags].dataBuffer.length = dlen;
  219.         fragment[nfrags].dataBuffer.bufAddr =
  220.             message->dataBuffer.bufAddr + dataOffset;
  221.  
  222.         dataOffset += dlen;
  223.         paramOffset += plen;
  224.         nfrags++;
  225.         }
  226.  
  227.         /*
  228.          * An inter-fragment delay is setup when going to a slower machine.
  229.          */
  230.         if (rpcDelay[spriteID] > rpcOutputRate) {
  231.         delay = rpcDelay[spriteID] - rpcOutputRate;
  232.         } else {
  233.         delay = 0;
  234.         }
  235.         /*
  236.          * Loop (again) to output the fragments.  Fragments are not output
  237.          * if their bit is set in the dontSendMask.  If dontSentMask
  238.          * would suppress all fragments, i.e. this is a keep-alive resend,
  239.          * we just send the last fragment.  Also, if this is a resend
  240.          * by the client and we haven't recieved a partial acknowledgment
  241.          * from the server we only resend the last fragment as a probe.
  242.          * This is for the case of large writes where the initial
  243.          * timeout period is too short.  We don't want to resend the
  244.          * whole packet unless we have to.
  245.          */
  246.         if ((dontSendMask == rpcCompleteMask[nfrags]) ||
  247.         ((rpcHdrPtr->flags & RPC_PLSACK) && (dontSendMask == 0))) {
  248.         sendFragMask = (1 << (nfrags - 1));
  249.         } else {
  250.         sendFragMask = ~dontSendMask;
  251.         }
  252.         for (fragID = 1, frag = 0;
  253.          frag < nfrags;
  254.          fragID <<= 1, frag++) {
  255.         if (fragID & sendFragMask) {
  256.  
  257.             fragRpcHdrPtr =
  258.                 (RpcHdr *)fragment[frag].rpcHdrBuffer.bufAddr;
  259.  
  260.             sendFragMask &= ~fragID;
  261.             /*
  262.              * Mark the last fragment of the batch so the receiver
  263.              * can check for a complete message.
  264.              */
  265.             if (sendFragMask == 0) {
  266.             fragRpcHdrPtr->flags |= RPC_LASTFRAG;
  267.             }
  268.             fragRpcHdrPtr->version =    rpc_NativeVersion;
  269.             fragRpcHdrPtr->flags =    rpcHdrPtr->flags;
  270.             fragRpcHdrPtr->clientID =    rpcHdrPtr->clientID;
  271.             fragRpcHdrPtr->serverID =    rpcHdrPtr->serverID;
  272.             fragRpcHdrPtr->channel =    rpcHdrPtr->channel;
  273.             fragRpcHdrPtr->serverHint =    rpcHdrPtr->serverHint;
  274.             fragRpcHdrPtr->bootID =    rpcHdrPtr->bootID;
  275.             fragRpcHdrPtr->ID =        rpcHdrPtr->ID;
  276.             fragRpcHdrPtr->delay =    rpcMyDelay;
  277.             fragRpcHdrPtr->numFrags =    nfrags;
  278.             fragRpcHdrPtr->fragMask =    fragID;
  279.             fragRpcHdrPtr->command =    rpcHdrPtr->command;
  280.  
  281.             /*
  282.              * The network routines expect an array of scatter/gather
  283.              * elements.  The RpcBufferSet is a struct of 4 of
  284.              * these so we cast its address into a (Net_ScatterGather *)
  285.              *
  286.              * Note that we only pass our mutex to Net on the last
  287.              * fragment.  With a mutex the packet transmission is
  288.              * synchronous, the Net_Output call doesn't return until
  289.              * the packet has been transmitted.  We only want this
  290.              * on the last fragment to prevent the obscure case where
  291.              * otherwise we might time out and retransmit before
  292.              * the packet is even on the wire.
  293.              */
  294.             status = Net_Output(spriteID,
  295.                 (Net_ScatterGather *)&fragment[frag], 4,
  296.                 ((fragRpcHdrPtr->flags & RPC_LASTFRAG) ?
  297.                  mutexPtr : (Sync_Semaphore *)NIL ),
  298.                  routePtr);
  299.             if (status != SUCCESS) {
  300.             return status;
  301.             }
  302.             /*
  303.              * Insert a delay after all but the last fragment.
  304.              * The master lock is released here to enable
  305.              * interrupts.  The ethernet driver needs an interrupt
  306.              * serviced in between the output of each packet.
  307.              */
  308.             RPC_TRACE(fragRpcHdrPtr, RPC_OUTPUT, "Fragout");
  309.             if (mutexPtr != (Sync_Semaphore *)NIL) {
  310.             if (Mach_AtInterruptLevel()) {
  311.                 panic(
  312.                   "RpcOutput, unlocking mutex at interrupt level");
  313.             } else {
  314.                 MASTER_UNLOCK(mutexPtr);
  315.             }
  316.             }
  317.             rpcLastDelay = delay;
  318.             if (delay &&
  319.             ((fragRpcHdrPtr->flags & RPC_LASTFRAG) == 0)) {
  320.             MACH_DELAY(delay);
  321.             }
  322.             if (mutexPtr != (Sync_Semaphore *)NIL) {
  323.             MASTER_LOCK(mutexPtr);
  324.             }
  325.         }
  326.         }
  327.     }
  328.     } else {
  329.     RpcHdrNew        *newHdrPtr;
  330.     /*
  331.      * No fragmenting.
  332.      */
  333.     rpcHdrPtr->numFrags = 0;
  334.     rpcHdrPtr->paramOffset = 0;
  335.     rpcHdrPtr->dataOffset = 0;
  336.     if (newVersion) {
  337.         newHdrPtr = (RpcHdrNew *) rpcHdrPtr;
  338.         newHdrPtr->paramStart = sizeof(RpcHdrNew);
  339.         newHdrPtr->dataStart = sizeof(RpcHdrNew) + newHdrPtr->paramSize;
  340.         newHdrPtr->version = rpc_NativeVersionNew;
  341.         message->rpcHdrBuffer.length = sizeof(RpcHdrNew);
  342.     } else {
  343.         /*
  344.          * Delete this once we get rid of newVersion.
  345.          */
  346.         rpcHdrPtr->version = rpc_NativeVersion;
  347.         message->rpcHdrBuffer.length = sizeof(RpcHdr);
  348.     }
  349.     if ((rpcHdrPtr->flags & RPC_TYPE) == RPC_ACK) {
  350.         /*
  351.          * Don't disturb the fragment mask.
  352.          */
  353.     } else {
  354.         rpcHdrPtr->fragMask = 0;
  355.     }
  356. #ifdef TIMESTAMP
  357.     RPC_NIL_TRACE(RPC_ETHER_OUT, "Ether output");
  358. #endif /* TIMESTAMP */
  359.     status = Net_Output(spriteID, (Net_ScatterGather *)message, 4, mutexPtr,
  360.         routePtr);
  361.     if (status != SUCCESS) {
  362.         return status;
  363.     }
  364.     RPC_TRACE(rpcHdrPtr, RPC_OUTPUT, "Output");
  365.     }
  366.     Net_ReleaseRoute(routePtr);
  367.     return(SUCCESS);
  368. }
  369.